package wangwenjun.phase3.executor.unchecked;

import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import util.ThreadUtil;

import java.util.concurrent.*;
import java.util.stream.IntStream;

/**
 * @author ChangLiang
 * @date 2020/6/23
 */
@Slf4j
public class UncheckedExceptionTestV4 {

    @Test
    @DisplayName("test customized MyThreadPoolExecutor")
    public void test4() throws InterruptedException {
        MyThreadPoolExecutor executorService = new MyThreadPoolExecutor(
                10, 10, 30, TimeUnit.SECONDS, new LinkedBlockingQueue<>());
        IntStream.range(0, 10).boxed().forEach(i -> executorService.execute(new MyRunnable(i,() -> {
            // 让 10 threads全部启动 防止线程被复用
            ThreadUtil.sleepForSeconds(2);
            if (i % 2 == 0) {
                int j = 1 / 0;
            } else {
                System.out.println(i);
            }
        })));
        executorService.shutdown();
        try {
            executorService.awaitTermination(10, TimeUnit.MINUTES);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        log.warn("test#finish");
    }

    private static class MyThreadPoolExecutor extends ThreadPoolExecutor {

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        }

        public MyThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) {
            super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        }

        @Override
        protected void beforeExecute(Thread t, Runnable r) {
            log.info("taskId:{} before execute", ((MyRunnable) r).getTaskId());
        }

        @Override
        protected void afterExecute(Runnable r, Throwable t) {
            if (t == null) {
                log.info("taskId:{} finished", ((MyRunnable) r).getTaskId());
            } else {
                log.error("taskId:{} error", ((MyRunnable) r).getTaskId());
                log.error(ThreadUtil.exceptionToString(t));
            }
        }
    }

    private final class MyRunnable implements Runnable {

        private final int taskId;

        private final Runnable runnable;

        public int getTaskId() {
            return this.taskId;
        }

        public MyRunnable(int taskId, Runnable runnable) {
            this.taskId = taskId;
            this.runnable = runnable;
        }

        @Override
        public void run() {
            runnable.run();
        }
    }
}
